From 3cfaf63e09773f7046e35b9287a94323840fcacf Mon Sep 17 00:00:00 2001 From: Keir Fraser Date: Mon, 23 Nov 2009 06:58:19 +0000 Subject: [PATCH] x86: enable directed EOI This patch enables directed EOI on latest processor. With this, the broadcast of EOI would be suppressed upon LAPIC EOI, so VMM is required to perform a directed EOI to the IOxAPIC generating the interrupt by writting to its EOI register.(Pls. refer SDM 3A 10.5.5) This is useful for ioapic_ack_old to avoid the spurious interrupt storm, which is the reason why ioapic_ack_new is used. Signed-Off-By: Zhai Edwin --- xen/arch/x86/apic.c | 25 +++++++++++++++++++++++++ xen/arch/x86/io_apic.c | 35 +++++++++++++++++++++++++++++++++-- xen/include/asm-x86/apic.h | 1 + xen/include/asm-x86/apicdef.h | 2 ++ xen/include/asm-x86/io_apic.h | 5 +++++ 5 files changed, 66 insertions(+), 2 deletions(-) diff --git a/xen/arch/x86/apic.c b/xen/arch/x86/apic.c index 64be332ca6..4c4a3de0d4 100644 --- a/xen/arch/x86/apic.c +++ b/xen/arch/x86/apic.c @@ -68,6 +68,7 @@ static int enable_local_apic __initdata = 0; /* -1=force-disable, +1=force-enabl int apic_verbosity; int x2apic_enabled __read_mostly = 0; +int directed_eoi_enabled __read_mostly = 0; /* * The following vectors are part of the Linux architecture, there @@ -348,6 +349,7 @@ void disable_local_APIC(void) } } +extern int ioapic_ack_new; /* * This is to verify that we're looking at a real local APIC. * Check these against your board if the CPUs aren't getting @@ -387,6 +389,18 @@ int __init verify_local_APIC(void) if (reg1 < 0x02 || reg1 == 0xff) return 0; + /* + * Detecting directed EOI on BSP: + * If having directed EOI support in lapic, force to use ioapic_ack_old, + * and enable the directed EOI for intr handling. + */ + if ( reg0 & APIC_LVR_DIRECTED_EOI ) + { + ioapic_ack_new = 0; + directed_eoi_enabled = 1; + printk("Enabled directed EOI with ioapic_ack_old on!\n"); + } + /* * The ID register is read/write in a real APIC. */ @@ -575,6 +589,17 @@ void __devinit setup_local_APIC(void) * Set spurious IRQ vector */ value |= SPURIOUS_APIC_VECTOR; + + /* + * Enable directed EOI + */ + if ( directed_eoi_enabled ) + { + value |= APIC_SPIV_DIRECTED_EOI; + apic_printk(APIC_VERBOSE, "Suppress EOI broadcast on CPU#%d\n", + smp_processor_id()); + } + apic_write_around(APIC_SPIV, value); /* diff --git a/xen/arch/x86/io_apic.c b/xen/arch/x86/io_apic.c index 9422fb4943..95a0a60938 100644 --- a/xen/arch/x86/io_apic.c +++ b/xen/arch/x86/io_apic.c @@ -197,6 +197,30 @@ static void unmask_IO_APIC_irq (unsigned int irq) spin_unlock_irqrestore(&ioapic_lock, flags); } +static void __eoi_IO_APIC_irq(unsigned int irq) +{ + struct irq_pin_list *entry = irq_2_pin + irq; + unsigned int pin, vector = IO_APIC_VECTOR(irq); + + for (;;) { + pin = entry->pin; + if (pin == -1) + break; + io_apic_eoi(entry->apic, vector); + if (!entry->next) + break; + entry = irq_2_pin + entry->next; + } +} + +static void eoi_IO_APIC_irq(unsigned int irq) +{ + unsigned long flags; + spin_lock_irqsave(&ioapic_lock, flags); + __eoi_IO_APIC_irq(irq); + spin_unlock_irqrestore(&ioapic_lock, flags); +} + static void clear_IO_APIC_pin(unsigned int apic, unsigned int pin) { struct IO_APIC_route_entry entry; @@ -1464,7 +1488,8 @@ static void mask_and_ack_level_ioapic_irq (unsigned int irq) if ( ioapic_ack_new ) return; - mask_IO_APIC_irq(irq); + if ( !directed_eoi_enabled ) + mask_IO_APIC_irq(irq); /* * It appears there is an erratum which affects at least version 0x11 @@ -1511,8 +1536,14 @@ static void end_level_ioapic_irq (unsigned int irq) if ( !ioapic_ack_new ) { - if ( !(irq_desc[irq].status & IRQ_DISABLED) ) + if ( irq_desc[irq].status & IRQ_DISABLED ) + return; + + if ( directed_eoi_enabled ) + eoi_IO_APIC_irq(irq); + else unmask_IO_APIC_irq(irq); + return; } diff --git a/xen/include/asm-x86/apic.h b/xen/include/asm-x86/apic.h index 99826c7b27..4bf4c70d43 100644 --- a/xen/include/asm-x86/apic.h +++ b/xen/include/asm-x86/apic.h @@ -23,6 +23,7 @@ extern int apic_verbosity; extern int x2apic_enabled; +extern int directed_eoi_enabled; extern void enable_x2apic(void); diff --git a/xen/include/asm-x86/apicdef.h b/xen/include/asm-x86/apicdef.h index 87a65997f0..4a026b1343 100644 --- a/xen/include/asm-x86/apicdef.h +++ b/xen/include/asm-x86/apicdef.h @@ -16,6 +16,7 @@ #define SET_xAPIC_ID(x) (((x)<<24)) #define APIC_LVR 0x30 #define APIC_LVR_MASK 0xFF00FF +#define APIC_LVR_DIRECTED_EOI (1 << 24) #define GET_APIC_VERSION(x) ((x)&0xFF) #define GET_APIC_MAXLVT(x) (((x)>>16)&0xFF) #define APIC_INTEGRATED(x) ((x)&0xF0) @@ -39,6 +40,7 @@ #define APIC_SPIV 0xF0 #define APIC_SPIV_FOCUS_DISABLED (1<<9) #define APIC_SPIV_APIC_ENABLED (1<<8) +#define APIC_SPIV_DIRECTED_EOI (1<<12) #define APIC_ISR 0x100 #define APIC_ISR_NR 0x8 /* Number of 32 bit ISR registers. */ #define APIC_TMR 0x180 diff --git a/xen/include/asm-x86/io_apic.h b/xen/include/asm-x86/io_apic.h index 6781ac1bac..e47ee0c168 100644 --- a/xen/include/asm-x86/io_apic.h +++ b/xen/include/asm-x86/io_apic.h @@ -147,6 +147,11 @@ static inline void io_apic_write(unsigned int apic, unsigned int reg, unsigned i *(IO_APIC_BASE(apic)+4) = value; } +static inline void io_apic_eoi(unsigned int apic, unsigned int vector) +{ + *(IO_APIC_BASE(apic)+16) = vector; +} + /* * Re-write a value: to be used for read-modify-write * cycles where the read already set up the index register. -- 2.30.2